package com.example.demoddd.application.services;

import cn.hutool.json.JSONUtil;
import com.example.demoddd.application.dto.Results;
import com.example.demoddd.application.dto.UserDto;
import com.example.demoddd.domain.userauth.model.User;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;


@RequiredArgsConstructor
@Validated
@Service
public class LoginApplicationService {
    private final AuthenticationManager authenticationManager;
    private final JwtEncoder jwtEncoder;
    //长token过期时间
    public static final long EXPIRY24 = 60L * 60 * 24;
    //短token过期时间
    public static final long EXPIRY1 = 60L * 60 * 1;

    public Results<List<TokenVo>> doLogin(UserDto userDto) {

        //登录未认证前使用 UsernamePasswordAuthenticationToken.unauthenticated 构建
        UsernamePasswordAuthenticationToken unauthenticateded = UsernamePasswordAuthenticationToken.unauthenticated(
                userDto.getEmail(),//可以自定义 使用的唯一性字段  例如邮箱
                userDto.getPassword() //密码
        );

        //使用authenticationManager.authenticate验证 UsernamePasswordAuthenticationToken
        Authentication authentication = authenticationManager.authenticate(unauthenticateded);
        //验证成功放入SecurityContex
        SecurityContextHolder.getContext().setAuthentication(authentication);
        User userDetails = (User) authentication.getPrincipal();

        List<TokenVo> tokenRes = getTokenVos(userDetails);

        /*jwtToken = Jwt.builder()
                .setSubject(userDetails.getUsername()) // 主题，通常是用户名
                .setIssuedAt(new Date()) // 签发时间
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10小时后过期
                .signWith(SignatureAlgorithm.RS256, "your-secret-key".getBytes()).compact();*/

        return Results.res(0, "成功", tokenRes);
    }

    private @NotNull List<TokenVo> getTokenVos(User userDetails) {
        String jwtToken = null;
        String jwtToken2 = null;

        System.out.println(JSONUtil.toJsonStr(userDetails));

        Instant now = Instant.now();
        long epochSecond = now.getEpochSecond();
        //角色列表字符串，必须用空格分隔
        //String scope = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));

        JwtClaimsSet claims = JwtClaimsSet.builder()
                //唯一id
                //.id()

                //签发者
                .issuer("JWT")

                //签发时间
                .issuedAt(now)

                //过期时间
                .expiresAt(now.plusSeconds(LoginApplicationService.EXPIRY1))

                //主题 可以是json数据
                .subject(JSONUtil.toJsonStr(userDetails))
                //绑定同一个值
                .claim("tokenGroup", epochSecond)
                .claim("tokenName", "TokenS")
                .build();
        //生成token
        jwtToken = jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();

        TokenVo tokenVoS = new TokenVo();
        tokenVoS.setName(claims.getClaimAsString("tokenName"));
        tokenVoS.setJwtToken(jwtToken);
        tokenVoS.setExpiry(EXPIRY1);

        JwtClaimsSet claims2 = JwtClaimsSet.builder()
                //唯一id
                //.id()

                //签发者
                .issuer("JWT")

                //签发时间
                .issuedAt(now)

                //过期时间
                .expiresAt(now.plusSeconds(LoginApplicationService.EXPIRY24))

                //主题 可以是json数据
                .subject(JSONUtil.toJsonStr(userDetails))
                //绑定同一个值
                .claim("tokenGroup", epochSecond)
                .claim("tokenName", "TokenL")

                .build();
        //生成token
        jwtToken2 = jwtEncoder.encode(JwtEncoderParameters.from(claims2)).getTokenValue();
        TokenVo tokenVoL = new TokenVo();
        tokenVoL.setName(claims2.getClaimAsString("tokenName"));
        tokenVoL.setJwtToken(jwtToken2);
        tokenVoL.setExpiry(EXPIRY24);

        //测试解析
        /*Jwt jwt = jwtDecoder.decode(jwtToken);
        String subject = jwt.getSubject();
        System.out.println(subject);*/


        List<TokenVo> tokenRes = new ArrayList<>();
        tokenRes.add(tokenVoS);
        tokenRes.add(tokenVoL);
        return tokenRes;
    }

    @Getter
    @Setter
    public static class TokenVo {
        private String name;
        private String jwtToken;
        //有效时长(秒)
        private Long expiry;
    }

    public Results refreshToken() {
        //获取认证过的用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        User userDetails = (User) authentication.getPrincipal();


        List<TokenVo> tokenRes = getTokenVos(userDetails);
        return Results.res(0, "成功", tokenRes);
    }
}
